package com.flyqiu.flow.core;

import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.flyqiu.common.bean.FlyQiuBeanManage;
import com.flyqiu.common.bean.FlyQiuSimpleBeanManage;
import com.flyqiu.common.transaction.FlyQiuTransactionManage;
import com.flyqiu.common.transaction.SimpleTransactionManage;
import com.flyqiu.flow.api.cache.FlyQiuFlowCacheManage;
import com.flyqiu.flow.api.candidate.FlyQiyFlowCandidateManage;
import com.flyqiu.flow.api.context.FlyQiuFlowGlobalContext;
import com.flyqiu.flow.api.deploy.FlyQiuFlowDeployManage;
import com.flyqiu.flow.api.element.FlyQiuFlowElementManage;
import com.flyqiu.flow.api.format.FlyQiuFlowBpmnFormatManage;
import com.flyqiu.flow.api.modelSource.FlowModelSourceManage;
import com.flyqiu.flow.api.script.FlyQiuFlowScriptActuatorManage;
import com.flyqiu.flow.api.script.FlyQiuFlowVarSerializeManage;
import com.flyqiu.flow.core.deploy.DefaultFlyQiuFlowDeployManage;
import com.flyqiu.flow.core.impl.DefaultFlowObjectFactory;
import com.flyqiu.flow.core.manage.*;
import com.flyqiu.flow.event.api.FlyQiuFlowEventManage;
import lombok.Getter;
import lombok.Setter;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.transaction.TransactionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.jdbc.support.JdbcTransactionManager;

import javax.sql.DataSource;

import static com.flyqiu.flow.core.DefaultFlyQiuFlowEngineImpl.FLY_QIU_FLOW_MAPPER;


/**
 * 流程全局上下文环境
 */
public class DefaultFlyQiuFlowGlobalContext implements FlyQiuFlowGlobalContext {


    @Getter
    @Setter
    protected FlyQiuFlowScriptActuatorManage flowScriptManage;
    @Setter
    protected FlyQiuFlowEventManage flowEventManage;
    @Setter
    protected FlyQiuBeanManage flowBeanManage;

    @Getter
    @Setter
    protected FlyQiuFlowElementManage flowElementManage;

    @Getter
    @Setter
    protected FlowModelSourceManage flowModelSourceManage;

    @Getter
    @Setter
    protected FlyQiuFlowCacheManage flowCacheManage;


    @Getter
    protected FlyQiuFlowDeployManage flowDeployManage;

    @Setter
    protected FlyQiuTransactionManage flowTransactionManage;

    //候选人加载器
    @Getter
    @Setter
    protected FlyQiyFlowCandidateManage flowCandidateManage;

    @Setter
    protected FlyQiuFlowVarSerializeManage flowVarSerializeManage;

    @Setter
    protected FlyQiuFlowBpmnFormatManage bpmnFormatManage;
    private static DefaultFlyQiuFlowGlobalContext context;

    public static DefaultFlyQiuFlowGlobalContext getInstance() {
        if (context == null) {
            throw new RuntimeException("DefaultFlyQiuFlowGlobalContext not created");
        }
        return context;
    }


    public DefaultFlyQiuFlowGlobalContext() {
        if (context != null) {
            throw new RuntimeException("DefaultFlyQiuFlowGlobalContext already exists, please do not create it again");
        }
        context = this;
    }


    public void setProcDeployConfig(FlyQiuFlowDeployManage procDeployManage) {
        this.flowDeployManage = procDeployManage;
    }


    @Override
    public FlyQiuFlowBpmnFormatManage getFlowBpmnFormatManage() {
        return bpmnFormatManage;
    }

    /**
     * 获取事件管理
     *
     * @return {@link FlyQiuFlowEventManage}
     */
    @Override
    public FlyQiuFlowEventManage getFlowEventManage() {
        return flowEventManage;
    }

    /**
     * 获取流程mapper管理
     *
     * @return {@link FlyQiuBeanManage}
     */
    public FlyQiuBeanManage getBeanManage() {
        return flowBeanManage;
    }

    /**
     * 事务管理
     *
     * @return {@link FlyQiuTransactionManage}
     */
    @Override
    public FlyQiuTransactionManage getTransactionManage() {
        return flowTransactionManage;
    }

    /**
     * 变量序列化管理
     *
     * @return {@link FlyQiuFlowVarSerializeManage}
     */
    @Override
    public FlyQiuFlowVarSerializeManage getFlowVarSerializeManage() {
        return flowVarSerializeManage;
    }

    public static FlyQiuFlowGlobalContext create(DataSource dataSource, TransactionFactory transactionFactory) {
        //初始化全局上下文
        DefaultFlyQiuFlowGlobalContext context = new DefaultFlyQiuFlowGlobalContext();
        //初始化流程事件管理器
        FlyQiuFlowEventManage flowEventManage = new DefaultFlyQiuFlowEventManage();
        context.setFlowEventManage(flowEventManage);

        //创建sqlSession
        SqlSessionTemplate sqlSession = createSqlSessionTemplate(dataSource, transactionFactory);
        //创建事务管理
        SimpleTransactionManage transactionManage = createTransactionManage(dataSource);
        context.setFlowTransactionManage(transactionManage);

        //bean对象管理器
        FlyQiuBeanManage procBeanManage = new FlyQiuSimpleBeanManage(sqlSession);
        context.setFlowBeanManage(procBeanManage);

        //初始化流程元素管理器
        FlyQiuFlowElementManage procElementManage = new DefaultFlyQiuFlowElementManage(new DefaultFlowObjectFactory());
        context.setFlowElementManage(procElementManage);


        //初始化流程发布管理器
        FlyQiuFlowDeployManage procDeployManage = new DefaultFlyQiuFlowDeployManage();
        context.setProcDeployConfig(procDeployManage);

        //初始化缓存管理器
        FlyQiuFlowCacheManage procCacheManage = new DefaultFlyQiuFlowCacheManage();
        context.setFlowCacheManage(procCacheManage);

        //初始化流程模型资源管理器
        FlowModelSourceManage procModelSourceManage = new DefaultFlyQiuFlowModelSourceManage(context);
        context.setFlowModelSourceManage(procModelSourceManage);

        //初始化脚本执行管理器
        FlyQiuFlowScriptActuatorManage scriptManage = new DefaultFlyQiuFlowScriptActuatorManage();
        context.setFlowScriptManage(scriptManage);

        //初始化流程格式管理器
        FlyQiuFlowBpmnFormatManage flyQiuFlowBpmnFormatManage = new DefaultFlyQiuFlowBpmnFormatManage();
        context.setBpmnFormatManage(flyQiuFlowBpmnFormatManage);

        //初始化变量序列化管理器
        FlyQiuFlowVarSerializeManage flyQiuFlowVarSerializeManage = new DefaultFlyQiuFlowVarSerializeManage();
        context.setFlowVarSerializeManage(flyQiuFlowVarSerializeManage);

        //初始化候选管理器
        FlyQiyFlowCandidateManage flyQiyFlowCandidateManage = new DefaultFlyQiuFlyCandidateManage();
        context.setFlowCandidateManage(flyQiyFlowCandidateManage);


        return context;
    }

    /**
     * 创建事务管理器
     *
     * @param dataSource 数据源
     * @return {@link SimpleTransactionManage}
     */
    public static SimpleTransactionManage createTransactionManage(DataSource dataSource) {
        JdbcTransactionManager transactionManager = new JdbcTransactionManager(dataSource);
        return new SimpleTransactionManage(transactionManager);
    }

    public static SqlSessionTemplate createSqlSessionTemplate(DataSource dataSource, TransactionFactory transactionFactory) {

        Environment environment = new Environment("startFlowEngine", transactionFactory, dataSource);
        MybatisConfiguration configuration = new MybatisConfiguration(environment);
        configuration.addMappers(FLY_QIU_FLOW_MAPPER);
        MybatisSqlSessionFactoryBuilder mybatisSqlSessionFactoryBuilder = new MybatisSqlSessionFactoryBuilder();
        GlobalConfig globalConfig = GlobalConfigUtils.getGlobalConfig(configuration);
        globalConfig.setSqlInjector(new DefaultSqlInjector());        //此参数会自动生成实现baseMapper的基础方法映射
        globalConfig.setIdentifierGenerator(DefaultIdentifierGenerator.getInstance());      //设置id生成器
        globalConfig.setSuperMapperClass(BaseMapper.class);  //设置超类mapper
        configuration.setLogImpl(StdOutImpl.class);
        SqlSessionFactory build = mybatisSqlSessionFactoryBuilder.build(configuration);
        return new SqlSessionTemplate(build);
    }

}
